package com.xiaoshu.netty0.server;

import com.xiaoshu.netty0.proto.OrderProto;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;

/**
 * code is far away from bug with the animal protecting
 * ┏┓　　　┏┓
 * ┏┛┻━━━┛┻┓
 * ┃　　　　　　　┃
 * ┃　　　━　　　┃
 * ┃　┳┛　┗┳　┃
 * ┃　　　　　　　┃
 * ┃　　　┻　　　┃
 * ┃　　　　　　　┃
 * ┗━┓　　　┏━┛
 * 　　┃　　　┃神兽保佑
 * 　　┃　　　┃代码无BUG！
 * 　　┃　　　┗━━━┓
 * 　　┃　　　　　　　┣┓
 * 　　┃　　　　　　　┏┛
 * 　　┗┓┓┏━┳┓┏┛
 * 　　　┃┫┫　┃┫┫
 * 　　　┗┻┛　┗┻┛
 *
 * @Description : 针对protobuf 协议的编解码操作
 * ---------------------------------
 * @Author : deane
 * @Date : Create in 2020/9/4 7:24
 * <p>
 * Copyright (C)2013-2020 小树盛凯科技 All rights reserved.
 */
public class NettyProtoServer {

    private void start(int port){
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class);
        serverBootstrap.option(ChannelOption.SO_BACKLOG, 1024);
        serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline pipeline = ch.pipeline();
                // 添加解码器
                pipeline.addLast(new ProtobufVarint32FrameDecoder());
                pipeline.addLast(new ProtobufDecoder(OrderProto.OrderRequest.getDefaultInstance()));
                // 添加编码器
                pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
                pipeline.addLast(new ProtobufEncoder());
                // 添加自己的业务处理类
                pipeline.addLast(new NettyProtoServerHandler());
            }
        });
        try {
            ChannelFuture future = serverBootstrap.bind(port).sync();
            System.out.println("[server start] listen :" + port);
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
        new NettyProtoServer().start(8080);
    }
}

class  NettyProtoServerHandler extends SimpleChannelInboundHandler<OrderProto.OrderRequest>{

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("[Client close] client is closed" + ctx.channel());
        ctx.close();
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, OrderProto.OrderRequest msg) throws Exception {
        OrderProto.OrderRequest request =  msg;
        System.out.println("Service Accept Client Order Request :[" + request + "]");
        OrderProto.OrderResponse.Builder builder = OrderProto.OrderResponse.newBuilder();
        builder.setOrderId(request.getOrderId());
        builder.setRespCode("200");
        builder.setDesc("Order Submit Successfully");
        ctx.writeAndFlush(builder);
    }
}
